#include "app_pool.h"
#include <stdlib.h>
#include <pthread.h>
#include "mqueue.h"
#include "log/log.h"

static char *pool_name = "/app_pool"; // 消息队列名称 以/dev/mqueue为根目录
static mqd_t mq_id;                  // 消息队列描述符
static pthread_t *thread_id;         // 线程池线程ID
static int thread_num;               // 线程池线程数量

// 线程函数
static void *thread_fun(void *arg)
{
    // 不断从消息队列中取出任务
    while (1)
    {
        // 从消息队列中取出任务
        Task task;
        mq_receive(mq_id, (char *)&task, sizeof(Task), NULL);
        // 执行任务
        task.task_fun(task.arg);
    }
    return NULL;
}

/**
 * @brief 初始化线程池
 * 1. 创建消息队列
 * 2. 创建多个分线程
 * @param size 线程池线程数量
 * @return int 0: 成功 -1: 失败
 */
int app_pool_init(int size)
{
    // 1. 创建消息队列
    struct mq_attr attr;            // 消息队列属性
    attr.mq_flags = 0;              // 非阻塞
    attr.mq_maxmsg = 10;            // 最大消息数
    attr.mq_msgsize = sizeof(Task); // 消息大小
    mq_id = mq_open(pool_name, O_RDWR | O_CREAT, 0644, &attr);
    if (mq_id == (mqd_t)-1)
    {
        log_debug("mq_open failed");
        return -1;
    }

    // 2. 创建多个分线程
    thread_num = size;
    thread_id = malloc(size * sizeof(pthread_t));
    if (thread_id == NULL)
    {
        log_debug("malloc failed");
        return -1;
    }
    for (int i = 0; i < thread_num; i++)
    {
        pthread_create(&thread_id[i], NULL, thread_fun, NULL);
    }
    return 0;
}

/**
 * @brief 线程池销毁
 * 1. 销毁消息队列
 * 2. 销毁所有线程
 * @return int 0: 成功 -1: 失败
 */
int app_pool_destroy(void)
{
    // 1. 销毁消息队列
    mq_close(mq_id);
    mq_unlink(pool_name);
    // 2. 取消停止所有线程
    for (int i = 0; i < thread_num; i++)
    {
        pthread_cancel(thread_id[i]);
        pthread_join(thread_id[i], NULL);
    }
    // 3. 释放线程池线程ID
    free(thread_id);

    return 0;
}

/**
 * @brief 线程池添加任务
 * 将任务添加到消息队列
 * @param task_fun 任务函数
 * @param arg 任务函数参数
 * @return int 0: 成功 -1: 失败
 */
int app_pool_addTask(int (*task_fun)(void *arg), void *arg)
{
    Task task;
    task.task_fun = task_fun;
    task.arg = arg;
    // 将任务添加到消息队列
    mq_send(mq_id, (char *)&task, sizeof(Task), 0);
    return 0;
}